home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 12 code / Components / Sources / ComponentTester.c next >
Encoding:
Text File  |  1994-12-02  |  41.0 KB  |  1,736 lines  |  [TEXT/MMCC]

  1. /************************************************************************************
  2.  
  3.     File:        ComponentTester.c
  4.  
  5.     Contains:    Component tester routines.
  6.  
  7.     Written by:    Gary Woodcock
  8.  
  9.     Copyright:    © 1992 by Apple Computer, Inc.
  10.  
  11.     Change History (most recent first):
  12.     
  13.             
  14.     Project settings for 68K ComponentTester.π
  15.         Project type:                Application
  16.         File name:                    68K Component Tester
  17.         Code model:                 Small, Smart or Large
  18.         Link Single Segment:        on or off
  19.         Project setup:
  20.             Segment 1 (Main Segment): ComponentTester.c, MacOS.lib, ComponentTester.rsrc 
  21.             
  22.     Project settings for PPC ComponentTester.π 
  23.         Project type:                Application
  24.         File name:                    Fat Component Tester
  25.         Main Entry Point            __start
  26.         Expand Uninitialized Data:     off
  27.         Export Symbols                None
  28.         Project setup:
  29.             Group 1 (Main Group): ComponentTester.c, 68K Component Tester (the 68K app) 
  30.             Group 2 (Group2): InterfaceLib, MathLib, ToolsLib.o, MWCRuntime.Lib, PPCGlue.c
  31.     
  32.  
  33.     Project settings for 68K ComponentTester_debug.π
  34.         Prefix file                    CW_Component_debug.h
  35.         Project type:                Application
  36.         File name:                    68K Component Tester Debug
  37.         Code model:                 Small, Smart or Large
  38.         Link Single Segment:        on or off
  39.         Project setup:
  40.             Segment 1 (Main Segment): ComponentTester.c, ComponentTester.rsrc 
  41.             Segment 2 (Libraries): MacOS.lib
  42.             Segment 3 (Math): MathComponent.c, MathComponentCommon.c, FatMathComponent.rsrc
  43.             Segment 4 (MoMath): MoMathComponent.c, FatMoMathComponent.rsrc 
  44.             Segment 5 (NuMath): NuMathComponent.c, FatNuMathComponent.rsrc 
  45.             
  46.     Project settings for PPC ComponentTester.π 
  47.         Prefix file                    CW_Component_debug.h
  48.         Project type:                Application
  49.         File name:                    Fat Component Tester Debug
  50.         Main Entry Point            __start
  51.         Expand Uninitialized Data:     off
  52.         Export Symbols                None
  53.         Project setup:
  54.             Group 1 (Main Group): ComponentTester.c, 68K Component Tester Debug (the 68K app) 
  55.             Group 2 (Libraries): InterfaceLib, MathLib, ToolsLib.o, MWCRuntime.Lib, PPCGlue.c
  56.             Group 3 (Math): MathComponent.c, MathComponentCommon.c
  57.             Group 4 (MoMath): MoMathComponent.c 
  58.             Group 5 (NuMath): NuMathComponent.c 
  59.  
  60.     ***Warning*** Fatxxx.rsrcs have an extended thng resource which 
  61.     is set to require both PPC and 68K code.  If you want to test the 68K 
  62.     component by itself, use xxx.rsrc, instead.
  63.  
  64.     Project settings, port to PPC and comments by
  65.     Mark Anderson
  66.     metrowerks
  67.     12/1/94
  68.     
  69. ************************************************************************************/
  70.  
  71.  
  72. //-----------------------------------------------------------------------
  73. // Includes
  74.  
  75.  
  76. #include "MathComponent.h"
  77. #include "MathComponentPrivate.h"
  78. #include "MoMathComponent.h"
  79. #include "MoMathComponentPrivate.h"
  80. #include "NuMathComponentPrivate.h"
  81. #include <Menus.h>
  82. #include <Windows.h>
  83. #include <QuickDraw.h>
  84. #include <OSEvents.h>
  85. #include <Resources.h>
  86. #include <Desk.h>
  87. #include <Fonts.h>
  88. #include <ToolUtils.h>
  89.  
  90. #ifndef THINK_C
  91.     #include <Packages.h>
  92. #endif THINK_C
  93.  
  94.  
  95. //-----------------------------------------------------------------------
  96. // Constants
  97.  
  98. // Maximum number of instances our app can open
  99. #define    kMaxInstances    10
  100.  
  101. // Menu bar
  102. enum
  103. {
  104.     kMenuBarID = 128
  105. };
  106.  
  107. // Menus
  108. enum
  109. {
  110.     kAppleID = 128,
  111.     kFileID,
  112.     kEditID,
  113.     kTestID,
  114.     kCanDoID,
  115.     kInstanceID
  116. };
  117.  
  118. // Apple menu items
  119. enum
  120. {
  121.     kAboutItem = 1
  122. };
  123.  
  124. // File menu items
  125. enum
  126. {
  127.     kOpenItem = 1,
  128.     kCloseItem,
  129.     
  130.     #ifdef DEBUG_IT
  131.         kOpenMathComponentItem = 4,
  132.         kOpenMoMathComponentItem,
  133.         kOpenNuMathComponentItem,
  134.         kCloseComponentItem,
  135.         kQuitItem = 9
  136.     #else
  137.         kOpenMoMathComponentItem = 4,
  138.         kOpenNuMathComponentItem,
  139.         kCloseComponentItem,
  140.         kQuitItem = 8
  141.     #endif DEBUG_IT
  142. };
  143.  
  144. // Edit menu items
  145. enum
  146. {
  147.     kUndoItem = 1,
  148.     kCutItem = 3,
  149.     kCopyItem,
  150.     kPasteItem,
  151.     kClearItem
  152. };
  153.  
  154. // Test menu items
  155. enum
  156. {
  157.     kGetNameItem = 1,
  158.     kGetInfoItem,
  159.     kGetVersionItem,
  160.     kGetCountItem,
  161.     kGetRefconItem,
  162.     kGetA5Item,
  163.     kCanDoItem = 8,
  164.     kDoDivideItem = 10,
  165.     kDoMultiplyItem,
  166.     kDoAddItem
  167. };
  168.  
  169. // Can Do hierarchical menu items
  170. enum
  171. {
  172.     kCanDoOpenItem = 1,
  173.     kCanDoCloseItem,
  174.     kCanDoCanDoItem,
  175.     kCanDoVersionItem,
  176.     kCanDoRegisterItem,
  177.     kCanDoTargetItem,
  178.     kCanDoDoDivideItem = 8,
  179.     kCanDoDoMultiplyItem,
  180.     kCanDoDoAddItem
  181. };
  182.  
  183. // Registration flags
  184. enum
  185. {
  186.     kRegisterLocally = 0,
  187.     kRegisterGlobally
  188. };
  189.  
  190. // Dialog IDs
  191. enum
  192. {
  193.     kAboutDialogID = 128,
  194.     kStatusDialogID,
  195.     kOpDialogID
  196. };
  197.  
  198. // Common DITL items
  199. enum
  200. {
  201.     kOKButton = 1,
  202.     kCancelButton,
  203.     kOKButtonOutline
  204. };
  205.  
  206. // DITL items for operations dialog
  207. enum
  208. {
  209.     kFirstNumBox = 4,
  210.     kSecondNumBox
  211. };
  212.  
  213. // DITL items for status dialog
  214. enum
  215. {
  216.     kStatusBox = 1
  217. };
  218.  
  219. // String list
  220. enum
  221. {
  222.     kStatusStrsID = 128
  223. };
  224.  
  225. // Strings
  226. enum
  227. {
  228.     kIdleStr = 1,
  229.     kFoundCompIDAndInstStr,
  230.     kDidNotFindCompIDStr,
  231.     kDidNotGetInstStr,
  232.     kClosedOKStr,
  233.     kErrorClosingInstStr,
  234.     kCompVersStr,
  235.     kInterfaceVersStr,
  236.     kCanDoOpenStr,
  237.     kCantDoOpenStr,
  238.     kCanDoCloseStr,
  239.     kCantDoCloseStr,
  240.     kCanDoCanDoStr,
  241.     kCantDoCanDoStr,
  242.     kCanDoVersionStr,
  243.     kCantDoVersionStr,
  244.     kCanDoRegisterStr,
  245.     kCantDoRegisterStr,
  246.     kCanDoTargetStr,
  247.     kCantDoTargetStr,
  248.     kNameStr,
  249.     kNoNameStr,
  250.     kInfoStr,
  251.     kNoInfoStr,
  252.     kRefconStr,
  253.     kThereIsStr,
  254.     kThereAreStr,
  255.     kInstanceStr,
  256.     kInstancesStr,
  257.     kA5Str,
  258.     kDivideResultStr,
  259.     kCanDoDoDivideStr,
  260.     kCantDoDoDivideStr,
  261.     kMultiplyResultStr,
  262.     kCanDoDoMultiplyStr,
  263.     kCantDoDoMultiplyStr,
  264.     kAddResultStr,
  265.     kCanDoDoAddStr,
  266.     kCantDoDoAddStr,
  267.     kCantOpenAnyMoreInstStr,
  268.     kCompDescStr,
  269.     kMathStr,
  270.     kMoMathStr,
  271.     kNuMathStr,
  272.     kKeyPhrase
  273. };
  274.  
  275. // Math component variants
  276. typedef    enum    MathType
  277. {
  278.     kMathComponent = 1,
  279.     kMoMathComponent,
  280.     kNuMathComponent
  281. }
  282. MathType;
  283.  
  284. //-----------------------------------------------------------------------
  285. // Globals
  286.  
  287. MenuHandle            gAppleMenu;
  288. MenuHandle            gFileMenu;
  289. MenuHandle            gEditMenu;
  290. MenuHandle            gTestMenu;
  291. MenuHandle            gCanDoMenu;
  292. MenuHandle            gInstanceMenu;
  293. EventRecord            gTheEvent;
  294. Component            gMathComponentID;
  295. Component            gMoMathComponentID;
  296. Component            gNuMathComponentID;
  297. ComponentInstance    gComponentInstance [kMaxInstances];
  298. ComponentInstance    gCurrentInstance;
  299. DialogPtr            gStatusDialog;
  300. GrafPtr                gSavedPort;
  301. Str255                gStatusStr;
  302. Rect                gStatusBox;
  303. Handle                gStatusText;
  304. Handle                gMathNameHdl;
  305. Handle                gMoMathNameHdl;
  306. Handle                gNuMathNameHdl;
  307. Handle                gInfoHdl;
  308. Str255                gKeyPhrase;
  309. Boolean                gQuitFlag;
  310.  
  311. //-----------------------------------------------------------------------
  312. // Prototypes
  313.  
  314. void                DoInit                    (void);
  315. void                DoMenuSetup                (void);
  316. void                HandleEvent                (void);
  317. void                HandleMouseDown            (void);
  318. void                AdjustMenus                (void);
  319. void                Enable                    (Handle        menu,
  320.                                              short        item,
  321.                                              Boolean    ok);
  322. void                HandleMenu                (long        menu);
  323. void                OpenStatus                (void);
  324. void                UpdateStatus            (void);
  325. void                DoAboutDialog            (void);
  326. void                OpenMathComponent        (MathType    whichOne);
  327. void                DoOperationDialog        (short        *numerator,
  328.                                              short        *denominator);
  329. static pascal void    DrawOKOutline            (DialogPtr    theDialog,
  330.                                              short        theItem);
  331. void                DoQuit                    (void);
  332. void                DecimalNumberToHexStr    (long        theDecimalNumber,
  333.                                              StringPtr    theHexStr);
  334. OSErr                HexStrToDecimalNumber    (StringPtr    theHexStr,
  335.                                              long        *theDecimalNumber);
  336.  
  337. //-----------------------------------------------------------------------
  338.  
  339. void main    (void)
  340. {
  341.     // Init
  342.     DoInit();
  343.     DoMenuSetup();
  344.     OpenStatus();
  345.     
  346.     // Eat events until done
  347.     do
  348.     {
  349.         HandleEvent();
  350.     }
  351.     while (!gQuitFlag);
  352.     
  353.     // Take off, eh?
  354.     ExitToShell();
  355. }
  356.  
  357. //-----------------------------------------------------------------------
  358.  
  359. void    DoInit    (void)
  360. {
  361.     short                    i;
  362.     ComponentDescription    mathDesc;
  363.     
  364.     // Set up quit flag
  365.     gQuitFlag = false;
  366.     
  367.     // MacMantra™
  368.     MaxApplZone();
  369.     InitGraf (&qd.thePort);
  370.     InitFonts();
  371.     FlushEvents (everyEvent, 0);
  372.     InitWindows();
  373.     InitMenus();
  374.     TEInit();
  375.     InitDialogs (0L);
  376.     InitCursor();
  377.     MoreMasters();
  378.     MoreMasters();
  379.     MoreMasters();
  380.     MoreMasters();
  381.     
  382.     // Get initial strings
  383.     GetIndString (gStatusStr, kStatusStrsID, kIdleStr);
  384.     GetIndString (gKeyPhrase, kStatusStrsID, kKeyPhrase);
  385.     
  386.     // Init instance stuff
  387.     gMathComponentID = 0L;
  388.     gMoMathComponentID = 0L;
  389.     gNuMathComponentID = 0L;
  390.     gCurrentInstance = 0L;
  391.     for (i = 0; i < kMaxInstances; i++)
  392.         gComponentInstance[i] = 0L;
  393.         
  394.     // Register (or find) our components
  395.     mathDesc.componentType = mathComponentType;
  396.     mathDesc.componentSubType = 0L;
  397.     mathDesc.componentManufacturer = 'appl';
  398.     mathDesc.componentFlags = 0L;
  399.     mathDesc.componentFlagsMask = 0L;
  400.     
  401.     // Are we debugging?
  402.     #ifdef DEBUG_IT
  403.     
  404.         if (gMathNameHdl == nil)
  405.         {
  406.             Str255    mathName = "\pMath Component";
  407.             
  408.             gMathNameHdl = NewHandle (sizeof (Str255));
  409.             BlockMove ((Ptr)&mathName, (Ptr)(*gMathNameHdl), mathName[0] + 1);
  410.         }
  411.         if (gMoMathNameHdl == nil)
  412.         {
  413.             Str255    moMathName = "\pMoMath Component";
  414.             
  415.             gMoMathNameHdl = NewHandle (sizeof (Str255));
  416.             BlockMove ((Ptr)&moMathName, (Ptr)(*gMoMathNameHdl), moMathName[0] + 1);
  417.         }
  418.         if (gNuMathNameHdl == nil)
  419.         {
  420.             Str255    nuMathName = "\pNuMath Component";
  421.             
  422.             gNuMathNameHdl = NewHandle (sizeof (Str255));
  423.             BlockMove ((Ptr)&nuMathName, (Ptr)(*gNuMathNameHdl), nuMathName[0] + 1);
  424.         }
  425.         if (gInfoHdl == nil)
  426.         {
  427.             Str255    mathInfo = "\pThis component provides simple math services.";
  428.             
  429.             gInfoHdl = NewHandle (sizeof (Str255));
  430.             BlockMove ((Ptr)&mathInfo, (Ptr)(*gInfoHdl), mathInfo[0] + 1);
  431.         }
  432.         
  433.         // Register the Math component
  434.         gMathComponentID = RegisterComponent (&mathDesc,
  435.             NewComponentRoutineProc(MathDispatcher), kRegisterLocally,
  436.             gMathNameHdl, gInfoHdl, nil);
  437.             
  438.         // Register the NuMath component
  439.         mathDesc.componentFlags = 0x80000000;
  440.         gNuMathComponentID = RegisterComponent (&mathDesc,
  441.             NewComponentRoutineProc(NuMathDispatcher), kRegisterLocally,
  442.             gNuMathNameHdl, gInfoHdl, nil);
  443.             
  444.         // Register the MoMath component
  445.         mathDesc.componentManufacturer = moMathComponentMfg;
  446.         mathDesc.componentFlags = 0L;
  447.         gMoMathComponentID = RegisterComponent (&mathDesc,
  448.             NewComponentRoutineProc(MoMathDispatcher), kRegisterLocally,
  449.             gMoMathNameHdl, gInfoHdl, nil);
  450.         
  451.     #else    // We're running as standalone components    
  452.     
  453.         // Find the NuMath component - Note that we won't be able to find the
  454.         // Math component, because the NuMath component captured it.  In essence,
  455.         // the NuMath component completely replaces the Math component (from an
  456.         // application point of view).    Also, you should note that it is perfectly
  457.         // acceptable to do a RegisterComponent call followed by a FindNextComponent
  458.         // call - if you use the same component description, and the
  459.         // RegisterComponent call was successful, then you'll get back the same
  460.         // component ID from FindNextComponent that you got from RegisterComponent.    
  461.         gNuMathComponentID = FindNextComponent (nil, &mathDesc);
  462.         
  463.         // Find the MoMath component
  464.         mathDesc.componentManufacturer = moMathComponentMfg;
  465.         gMoMathComponentID = FindNextComponent (nil, &mathDesc);    
  466.                 
  467.     #endif DEBUG_IT    
  468. }
  469.  
  470. //-----------------------------------------------------------------------
  471.  
  472. void    DoMenuSetup    (void)
  473. {    
  474.     Handle    theMenuBar = GetNewMBar (kMenuBarID);
  475.     
  476.     // Set up our menus
  477.     SetMenuBar (theMenuBar);
  478.     gAppleMenu = GetMHandle (kAppleID);
  479.     gFileMenu = GetMHandle (kFileID);
  480.     
  481.     // We don't need the "Open Math Component" item unless
  482.     // we're debugging
  483.     #ifndef DEBUG_IT
  484.         DelMenuItem (gFileMenu, 4);
  485.     #endif DEBUG_IT
  486.     
  487.     gEditMenu = GetMHandle (kEditID);
  488.     gTestMenu = GetMHandle (kTestID);
  489.     gInstanceMenu = GetMHandle (kInstanceID);
  490.     gCanDoMenu = GetMenu (kCanDoID);
  491.     InsertMenu (gCanDoMenu, hierMenu);
  492.     AddResMenu (gAppleMenu, 'DRVR');
  493.     DrawMenuBar();
  494. }
  495.  
  496. //-----------------------------------------------------------------------
  497.  
  498. void    HandleEvent    (void)
  499. {
  500.     Boolean    ok = false;
  501.  
  502.     // Do system stuff
  503.     HiliteMenu (0);
  504.     SystemTask();
  505.     
  506.     // Suck an event
  507.     ok = WaitNextEvent (everyEvent, &gTheEvent, 0, 0);
  508.     if (ok)
  509.     {
  510.         // What was it?
  511.         switch (gTheEvent.what)
  512.         {
  513.             case mouseDown:
  514.             {
  515.                 HandleMouseDown();
  516.                 break;
  517.             }
  518.             case keyDown:
  519.             case autoKey:
  520.             {
  521.                 char    theChar = gTheEvent.message & charCodeMask;
  522.                 long    theMenu = MenuKey (theChar);
  523.  
  524.                 HandleMenu (theMenu);                
  525.                 break;
  526.             }
  527.             case updateEvt:
  528.             {
  529.                 if (IsDialogEvent (&gTheEvent))
  530.                 {
  531.                     // Update the status dialog
  532.                     GetPort (&gSavedPort);
  533.                     SetPort (gStatusDialog);
  534.                     BeginUpdate (gStatusDialog);
  535.                     InsetRect (&gStatusBox, -2, -2);
  536.                     FrameRect (&gStatusBox);
  537.                     InsetRect (&gStatusBox, 2, 2);
  538.                     EraseRect (&gStatusBox);
  539.                     SetIText (gStatusText, gStatusStr);
  540.                     EndUpdate (gStatusDialog);
  541.                     SetPort (gSavedPort);
  542.                 }
  543.             }
  544.             default:    // We don't really care about any other events
  545.             {
  546.                 break;
  547.             }
  548.         }
  549.     }
  550. }
  551.  
  552. //-----------------------------------------------------------------------
  553.  
  554. void    HandleMouseDown    (void)
  555. {    
  556.     WindowPtr    theWindow;
  557.     short        windowCode = FindWindow (gTheEvent.where, &theWindow);
  558.     
  559.     // Where was the mouse down?
  560.     switch (windowCode)
  561.     {
  562.         case inSysWindow:
  563.         { 
  564.             SystemClick (&gTheEvent, theWindow);
  565.             break;
  566.         }
  567.         case inMenuBar:
  568.         {
  569.             AdjustMenus();
  570.             HandleMenu (0L);
  571.             break;
  572.         }
  573.         case inDrag:
  574.         {
  575.             DragWindow (theWindow, gTheEvent.where, &(qd.screenBits.bounds));
  576.             break;
  577.         }
  578.         case inGoAway:
  579.         {
  580.             if ((theWindow == gStatusDialog) && 
  581.                 TrackGoAway (gStatusDialog, gTheEvent.where))
  582.             {
  583.                 DisposDialog (gStatusDialog);
  584.                 gStatusDialog = nil;
  585.             }
  586.             break;
  587.         }
  588.         default:
  589.         {
  590.             break;
  591.         }
  592.     }
  593. }
  594.  
  595. //-----------------------------------------------------------------------
  596.  
  597. void    AdjustMenus    (void)
  598. {
  599.     register WindowPeek        wp = nil;
  600.     short                    kind = 0;
  601.     Boolean                    DA = false;
  602.     ComponentDescription    compDesc;
  603.     ComponentResult            result = noErr;
  604.     
  605.     // What kind of window is frontmost?
  606.     wp = (WindowPeek) FrontWindow();
  607.     kind = wp ? wp->windowKind : 0;
  608.     DA = kind < 0;
  609.     
  610.     // Set our menu item states appropriately
  611.     
  612.     // Apple menu
  613.     Enable ((Handle) gAppleMenu, kAboutItem, true);    
  614.     
  615.     // File menu
  616.     Enable ((Handle) gFileMenu, kOpenItem, (gStatusDialog == nil) ? true : false);
  617.     Enable ((Handle) gFileMenu, kCloseItem, DA || ((gStatusDialog != nil) ? true : false));
  618.     
  619.     #ifdef DEBUG_IT
  620.         Enable ((Handle) gFileMenu, kOpenMathComponentItem, true);
  621.     #endif DEBUG_IT
  622.     
  623.     Enable ((Handle) gFileMenu, kOpenMoMathComponentItem, true);
  624.     Enable ((Handle) gFileMenu, kOpenNuMathComponentItem, true);
  625.     Enable ((Handle) gFileMenu, kCloseComponentItem, (gCurrentInstance != 0L) ? true : false);
  626.     Enable ((Handle) gFileMenu, kQuitItem, true);
  627.  
  628.     // Edit menu
  629.     Enable ((Handle) gEditMenu, 1, DA);
  630.     Enable ((Handle) gEditMenu, 3, DA);
  631.     Enable ((Handle) gEditMenu, 4, DA);
  632.     Enable ((Handle) gEditMenu, 5, DA);
  633.     Enable ((Handle) gEditMenu, 6, DA);
  634.     
  635.     // Test menu
  636.     Enable ((Handle) gTestMenu, kCanDoItem, (gCurrentInstance != 0L) ? true : false);
  637.     Enable ((Handle) gTestMenu, kGetVersionItem, (gCurrentInstance != 0L) ? true : false);
  638.     Enable ((Handle) gTestMenu, kGetNameItem, (gCurrentInstance != 0L) ? true : false);
  639.     Enable ((Handle) gTestMenu, kGetInfoItem, (gCurrentInstance != 0L) ? true : false);
  640.     Enable ((Handle) gTestMenu, kGetRefconItem, (gCurrentInstance != 0L) ? true : false);
  641.     Enable ((Handle) gTestMenu, kGetCountItem, (gCurrentInstance != 0L) ? true : false);
  642.     Enable ((Handle) gTestMenu, kGetA5Item, (gCurrentInstance != 0L) ? true : false);
  643.     Enable ((Handle) gTestMenu, kDoDivideItem, (gCurrentInstance != 0L) ? true : false);
  644.     Enable ((Handle) gTestMenu, kDoMultiplyItem, (gCurrentInstance != 0L) ? true : false);
  645.  
  646.     // Only enable add stuff if a MoMath component is around
  647.     if (gCurrentInstance != 0L)
  648.     {
  649.         result = GetComponentInfo ((Component)(gCurrentInstance), &compDesc, nil, nil, nil);
  650.         if (compDesc.componentManufacturer == moMathComponentMfg)
  651.         {
  652.             Enable ((Handle) gTestMenu, kDoAddItem, true);
  653.         }
  654.         else
  655.         {
  656.             Enable ((Handle) gTestMenu, kDoAddItem, false);
  657.         }
  658.     }
  659.     else
  660.     {
  661.         Enable ((Handle) gTestMenu, kDoAddItem, false);
  662.     }
  663.     
  664.     // Figure out which item is checked in the Instance menu
  665.     if (CountMItems (gInstanceMenu) > 0)
  666.     {
  667.         short    i;
  668.         short    j;
  669.         long    tempInst;
  670.         Str255    menuItemStr;
  671.         Str255    tempInstStr;
  672.         
  673.         // Enable the menu
  674.         EnableItem (gInstanceMenu, 0);
  675.         
  676.         // Examine each item
  677.         for (i = 1; i <= CountMItems (gInstanceMenu); i++)
  678.         {
  679.             Boolean    foundKey = false;
  680.             
  681.             // Uncheck the item
  682.             CheckItem (gInstanceMenu, i, false);
  683.             
  684.             // Get the item string
  685.             GetItem (gInstanceMenu, i, menuItemStr);
  686.             
  687.             // Extract the instance number from the menu string
  688.             GetItem (gInstanceMenu, i, menuItemStr);
  689.             for (j = 1; j <= menuItemStr[0]; j++)
  690.             {
  691.                 if ((gKeyPhrase[1] == menuItemStr[j]) &&
  692.                     (gKeyPhrase[2] == menuItemStr[j + 1]) &&
  693.                     (gKeyPhrase[3] == menuItemStr[j + 2]) &&
  694.                     (gKeyPhrase[4] == menuItemStr[j + 3]) &&
  695.                     (gKeyPhrase[5] == menuItemStr[j + 4]))
  696.                 {
  697.                     foundKey = true;
  698.                     break;
  699.                 }
  700.             }
  701.             
  702.             // Did we find the phrase key?
  703.             if (foundKey)
  704.             {
  705.                 // Copy the instance string
  706.                 BlockMove ((Ptr)&menuItemStr[j + 5], (Ptr)&tempInstStr[1],
  707.                     menuItemStr[menuItemStr[0] - (j + 4)]);
  708.                 tempInstStr[0] = menuItemStr[0] - (j + 4);
  709.                 
  710.                 // Is it the current instance?
  711.                 HexStrToDecimalNumber ((StringPtr)&tempInstStr, &tempInst);
  712.                 if (tempInst == (long)(gCurrentInstance))
  713.                 {
  714.                     // Check it
  715.                     CheckItem (gInstanceMenu, i, true);
  716.                 }
  717.             }                            
  718.         }
  719.     }
  720.     else    // No instances are currently open, so dim this menu
  721.     {
  722.         DisableItem (gInstanceMenu, 0);
  723.     }
  724.     DrawMenuBar();
  725. }
  726.  
  727. //-----------------------------------------------------------------------
  728.  
  729. void    Enable    (Handle        menu, 
  730.                  short        item, 
  731.                  Boolean    ok)
  732. {
  733.     // Utility routine to enable and disable menu items
  734.     if (ok)
  735.     {
  736.         EnableItem ((MenuHandle) menu, item);
  737.     }
  738.     else
  739.     {
  740.         DisableItem ((MenuHandle) menu, item);
  741.     }
  742. }
  743.  
  744. //-----------------------------------------------------------------------
  745.  
  746. void    HandleMenu    (long    theMenu)
  747. {    
  748.     long                    mSelect;
  749.     short                    menuID;
  750.     short                    menuItem;
  751.     ComponentResult            result = noErr;    
  752.     Str255                    menuItemStr;
  753.     Str255                    tempStr;
  754.     short                    i;
  755.     short                    j;
  756.     ComponentDescription    mathDesc;
  757.     
  758.     // Did we get a menu?
  759.     if (theMenu == 0L)
  760.     {
  761.         // Nope, get it from menu select
  762.         mSelect = MenuSelect (gTheEvent.where);
  763.     }
  764.     else
  765.     {
  766.         // Yep, use it
  767.         mSelect = theMenu;
  768.     }
  769.     
  770.     // Decode it
  771.     menuID = HiWord (mSelect);
  772.     menuItem = LoWord (mSelect);
  773.     
  774.     // Which menu is it?
  775.     switch (menuID)
  776.     {
  777.         case kAppleID:
  778.         {
  779.             if (menuItem == kAboutItem)
  780.             {
  781.                 DoAboutDialog();
  782.             }
  783.             else    // It's a DA
  784.             {
  785.                 Str255    name;
  786.                 
  787.                 // Open the DA
  788.                 GetPort (&gSavedPort);
  789.                 GetItem (gAppleMenu, menuItem, name);
  790.                 OpenDeskAcc (name);
  791.                 SetPort (gSavedPort);
  792.             }
  793.             break;
  794.         }
  795.         case kFileID:
  796.         {
  797.             switch (menuItem)
  798.             {
  799.                 case kOpenItem:
  800.                 {
  801.                     // Open the status dialog
  802.                     OpenStatus();
  803.                     break;
  804.                 }
  805.                 case kCloseItem:
  806.                 {
  807.                     WindowPeek    frontWindow = (WindowPeek) FrontWindow();
  808.                     
  809.                     // Is a window up?
  810.                     if (frontWindow == 0L)
  811.                     {
  812.                         break;
  813.                     }
  814.                     else    // Yep
  815.                     {
  816.                         // What kind of window is it?
  817.                         if (frontWindow->windowKind < 0)
  818.                         {
  819.                             // It's a DA
  820.                             CloseDeskAcc (frontWindow->windowKind);
  821.                         }
  822.                         else
  823.                         {
  824.                             // Is it the status dialog?
  825.                             if (gStatusDialog != nil)
  826.                             {
  827.                                 // Close it
  828.                                 DisposDialog (gStatusDialog);
  829.                                 gStatusDialog = nil;
  830.                             }
  831.                             
  832.                             // Update the menus
  833.                             AdjustMenus();
  834.                         }
  835.                     }
  836.                     break;
  837.                   }
  838.                   
  839.                   #ifdef DEBUG_IT
  840.                     case kOpenMathComponentItem:
  841.                     {
  842.                         OpenMathComponent (kMathComponent);
  843.                         break;
  844.                     }
  845.                 #endif DEBUG_IT
  846.                 
  847.                 case kOpenMoMathComponentItem:
  848.                 {
  849.                     OpenMathComponent (kMoMathComponent);
  850.                     break;
  851.                 }
  852.                 
  853.                 case kOpenNuMathComponentItem:
  854.                 {
  855.                     OpenMathComponent (kNuMathComponent);
  856.                     break;
  857.                 }
  858.                 
  859.                 case kCloseComponentItem:
  860.                 {
  861.                     if (gCurrentInstance != 0L)
  862.                     {
  863.                         // Close the component instance
  864.                         result = CloseComponent (gCurrentInstance);
  865.                         if (result != noErr)
  866.                         {
  867.                             GetIndString (gStatusStr, kStatusStrsID, kErrorClosingInstStr);
  868.                         }
  869.                         else
  870.                         {
  871.                             GetIndString (gStatusStr, kStatusStrsID, kClosedOKStr);
  872.                         }
  873.                         UpdateStatus();
  874.                         
  875.                         // Delete this instance from the instance menu
  876.                         DecimalNumberToHexStr ((long) gCurrentInstance, (StringPtr)&tempStr);
  877.                         for (i = 1; i <= CountMItems (gInstanceMenu); i++)
  878.                         {
  879.                             Str255    tempInstStr;
  880.                             Boolean    foundKey = false;
  881.                             
  882.                             // Extract the instance number from the menu item string
  883.                             GetItem (gInstanceMenu, i, menuItemStr);
  884.                             for (j = 1; j <= menuItemStr[0]; j++)
  885.                             {
  886.                                 if ((gKeyPhrase[1] == menuItemStr[j]) &&
  887.                                     (gKeyPhrase[2] == menuItemStr[j + 1]) &&
  888.                                     (gKeyPhrase[3] == menuItemStr[j + 2]) &&
  889.                                     (gKeyPhrase[4] == menuItemStr[j + 3]) &&
  890.                                     (gKeyPhrase[5] == menuItemStr[j + 4]))
  891.                                 {
  892.                                     foundKey = true;
  893.                                     break;
  894.                                 }
  895.                             }
  896.                             
  897.                             // Did we find the phrase key?
  898.                             if (foundKey)
  899.                             {
  900.                                 // Copy the instance string
  901.                                 BlockMove ((Ptr)&menuItemStr[j + 5], (Ptr)&tempInstStr[1],
  902.                                     menuItemStr[menuItemStr[0] - (j + 4)]);
  903.                                 tempInstStr[0] = menuItemStr[0] - (j + 4);
  904.                                 
  905.                                 // Is this the instance we're closing?
  906.                                 if (RelString (tempInstStr, tempStr, true, true) == 0)
  907.                                 {
  908.                                     // Delete this item from the menu
  909.                                     DelMenuItem (gInstanceMenu, i);
  910.                                     break;
  911.                                 }
  912.                             }                            
  913.                         }
  914.                         
  915.                         // Clear out its slot
  916.                         for (i = 0; i < kMaxInstances; i++)
  917.                         {
  918.                             if (gCurrentInstance == gComponentInstance[i])
  919.                             {
  920.                                 gComponentInstance[i] = 0L;
  921.                                 break;
  922.                             }
  923.                         }
  924.                         gCurrentInstance = 0L;
  925.                         
  926.                         // Set up on another instance in the menu (if there is one)
  927.                         for (i = 0; i < kMaxInstances; i++)
  928.                         {
  929.                             if (gComponentInstance[i] != 0L)
  930.                             {
  931.                                 gCurrentInstance = gComponentInstance[i];
  932.                                 break;
  933.                             }
  934.                         }
  935.                     }
  936.                     
  937.                     // Update the menus
  938.                     AdjustMenus();
  939.                     break;
  940.                 }
  941.                 case kQuitItem:
  942.                 {
  943.                     // We're outta here
  944.                     DoQuit();
  945.                     break;
  946.                 }
  947.                 default:
  948.                 {
  949.                     break;
  950.                 }
  951.             }
  952.             break;
  953.           }    
  954.         case kEditID:
  955.         {
  956.             if (!SystemEdit (menuItem - 1))
  957.             {
  958.                 // We don't really do anything here - feel free to implement something
  959.                 // yourself if you want
  960.                 SysBeep(5);
  961.             }
  962.             break;
  963.         }
  964.         case kTestID:
  965.         {
  966.             Str255    tempStr;
  967.             
  968.             switch (menuItem)
  969.             {
  970.                 case kGetVersionItem:
  971.                 {
  972.                     long    version = GetComponentVersion (gCurrentInstance);
  973.                     
  974.                     tempStr[0] = 0;
  975.                     GetIndString (gStatusStr, kStatusStrsID, kCompVersStr);
  976.                     NumToString ((version >> 16), tempStr);
  977.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  978.                         tempStr[0]);
  979.                     gStatusStr[0] += tempStr[0];
  980.                     GetIndString (tempStr, kStatusStrsID, kInterfaceVersStr);
  981.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  982.                         tempStr[0]);
  983.                     gStatusStr[0] += tempStr[0];
  984.                     NumToString ((version & 0x0000FFFF), tempStr);
  985.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  986.                         tempStr[0]);
  987.                     gStatusStr[0] += tempStr[0] + 1;
  988.                     gStatusStr[gStatusStr[0]] = '.';
  989.                     UpdateStatus();
  990.                     break;
  991.                 }
  992.                 case kGetNameItem:
  993.                 {
  994.                     Handle    nameHdl = NewHandle (sizeof (Str255));
  995.                     
  996.                     if (nameHdl != nil)
  997.                     {
  998.                         result = GetComponentInfo ((Component) gCurrentInstance, 
  999.                             nil, nameHdl, nil, nil);
  1000.                         HLock (nameHdl);
  1001.                         if ((**nameHdl) == 0)
  1002.                         {
  1003.                             GetIndString (gStatusStr, kStatusStrsID, kNoNameStr);
  1004.                         }
  1005.                         else
  1006.                         {
  1007.                             GetIndString (gStatusStr, kStatusStrsID, kNameStr);
  1008.                             BlockMove ((Ptr)&((**((Str255**)(nameHdl)))[1]), 
  1009.                                 (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1010.                                 (**((Str255**)(nameHdl)))[0]);
  1011.                             gStatusStr[0] += (**((Str255**)(nameHdl)))[0] + 2;
  1012.                             gStatusStr[gStatusStr[0] - 1] = '”';
  1013.                             gStatusStr[gStatusStr[0]] = '.';
  1014.                         }
  1015.                         HUnlock (nameHdl);
  1016.                         DisposHandle (nameHdl);
  1017.                     }
  1018.                     UpdateStatus();
  1019.                     break;
  1020.                 }
  1021.                 case kGetInfoItem:
  1022.                 {
  1023.                     Handle    infoHdl = NewHandle (sizeof (Str255));
  1024.                     
  1025.                     if (infoHdl != nil)
  1026.                     {
  1027.                         result = GetComponentInfo ((Component) gCurrentInstance, 
  1028.                             nil, nil, infoHdl, nil);
  1029.                         HLock (infoHdl);
  1030.                         if ((**((Str255**)(infoHdl)))[0] == 0)
  1031.                         {
  1032.                             GetIndString (gStatusStr, kStatusStrsID, kNoInfoStr);
  1033.                         }
  1034.                         else
  1035.                         {
  1036.                             GetIndString (gStatusStr, kStatusStrsID, kInfoStr);
  1037.                             BlockMove ((Ptr)&((**((Str255**)(infoHdl)))[1]), 
  1038.                                 (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1039.                                 (**((Str255**)(infoHdl)))[0]);
  1040.                             gStatusStr[0] += (**((Str255**)(infoHdl)))[0] + 2;
  1041.                             gStatusStr[gStatusStr[0] - 1] = '”';
  1042.                             gStatusStr[gStatusStr[0]] = '.';
  1043.                         }
  1044.                         HUnlock (infoHdl);
  1045.                         DisposHandle (infoHdl);
  1046.                     }
  1047.                     UpdateStatus();
  1048.                     break;
  1049.                 }
  1050.                 case kGetRefconItem:
  1051.                 {
  1052.                     long    refcon = GetComponentRefcon ((Component)gCurrentInstance);
  1053.                     
  1054.                     NumToString (refcon, tempStr);
  1055.                     GetIndString (gStatusStr, kStatusStrsID, kRefconStr);
  1056.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1057.                         tempStr[0]);
  1058.                     gStatusStr[0] += tempStr[0] + 1;
  1059.                     gStatusStr[gStatusStr[0]] = '.';
  1060.                     UpdateStatus();
  1061.                     break;
  1062.                 }
  1063.                 case kGetCountItem:
  1064.                 {
  1065.                     long    instCount = CountComponentInstances ((Component) gCurrentInstance);
  1066.                     
  1067.                     NumToString (instCount, tempStr);
  1068.                     if (instCount == 1)
  1069.                     {
  1070.                         GetIndString (gStatusStr, kStatusStrsID, kThereIsStr);
  1071.                         BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1072.                             tempStr[0]);
  1073.                         gStatusStr[0] += tempStr[0];
  1074.                         GetIndString (tempStr, kStatusStrsID, kInstanceStr);
  1075.                         BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1076.                             tempStr[0]);
  1077.                     }
  1078.                     else
  1079.                     {
  1080.                         GetIndString (gStatusStr, kStatusStrsID, kThereAreStr);
  1081.                         BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1082.                             tempStr[0]);
  1083.                         gStatusStr[0] += tempStr[0];
  1084.                         GetIndString (tempStr, kStatusStrsID, kInstancesStr);
  1085.                         BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1086.                             tempStr[0]);
  1087.                     }
  1088.                     gStatusStr[0] += tempStr[0];
  1089.                     UpdateStatus();
  1090.                     break;
  1091.                 }
  1092.                 case kGetA5Item:
  1093.                 {
  1094.                     long    compA5 = GetComponentInstanceA5 (gCurrentInstance);
  1095.                     
  1096.                     NumToString (compA5, tempStr);
  1097.                     GetIndString (gStatusStr, kStatusStrsID, kA5Str);
  1098.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1099.                         tempStr[0]);
  1100.                     gStatusStr[0] += tempStr[0] + 1;
  1101.                     gStatusStr[gStatusStr[0]] = '.';
  1102.                     UpdateStatus();
  1103.                     break;
  1104.                 }
  1105.                 case kDoDivideItem:
  1106.                 {
  1107.                     short    numerator;
  1108.                     short    denominator;
  1109.                     short    quotient;
  1110.                     
  1111.                     DoOperationDialog (&numerator, &denominator);
  1112.                     result = DoDivide (gCurrentInstance, numerator, denominator, 
  1113.                         "ient);
  1114.                     NumToString ((long) quotient, tempStr);
  1115.                     GetIndString (gStatusStr, kStatusStrsID, kDivideResultStr);
  1116.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1117.                         tempStr[0]);
  1118.                     gStatusStr[0] += tempStr[0] + 1;
  1119.                     gStatusStr[gStatusStr[0]] = '.';
  1120.                     UpdateStatus();
  1121.                     break;
  1122.                 }
  1123.                 case kDoMultiplyItem:
  1124.                 {
  1125.                     short    firstNum;
  1126.                     short    secondNum;
  1127.                     short    multiplyResult;
  1128.                     
  1129.                     DoOperationDialog (&firstNum, &secondNum);
  1130.                     result = DoMultiply (gCurrentInstance, firstNum, secondNum, 
  1131.                         &multiplyResult);
  1132.                     NumToString ((long) multiplyResult, tempStr);
  1133.                     GetIndString (gStatusStr, kStatusStrsID, kMultiplyResultStr);
  1134.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1135.                         tempStr[0]);
  1136.                     gStatusStr[0] += tempStr[0] + 1;
  1137.                     gStatusStr[gStatusStr[0]] = '.';
  1138.                     UpdateStatus();    
  1139.                     break;
  1140.                 }
  1141.                 case kDoAddItem:
  1142.                 {
  1143.                     short    firstNum;
  1144.                     short    secondNum;
  1145.                     short    addResult;
  1146.                     
  1147.                     DoOperationDialog (&firstNum, &secondNum);
  1148.                     result = DoAdd (gCurrentInstance, firstNum, secondNum, &addResult);
  1149.                     NumToString ((long) addResult, tempStr);
  1150.                     GetIndString (gStatusStr, kStatusStrsID, kAddResultStr);
  1151.                     BlockMove ((Ptr)&tempStr[1], (Ptr)&gStatusStr[gStatusStr[0] + 1],
  1152.                         tempStr[0]);
  1153.                     gStatusStr[0] += tempStr[0] + 1;
  1154.                     gStatusStr[gStatusStr[0]] = '.';
  1155.                     UpdateStatus();
  1156.                     break;
  1157.                 }
  1158.                 default:
  1159.                 {
  1160.                     break;
  1161.                 }
  1162.             }
  1163.             break;
  1164.         }
  1165.         case kInstanceID:
  1166.         {
  1167.             Str255    instanceStr;
  1168.             Boolean    foundKey = false;
  1169.             
  1170.             // Get the menu item string
  1171.             GetItem (gInstanceMenu, menuItem, menuItemStr);
  1172.             
  1173.             // Find the key phrase
  1174.             for (i = 1; i <= menuItemStr[0]; i++)
  1175.             {
  1176.                 if ((gKeyPhrase[1] == menuItemStr[i]) &&
  1177.                     (gKeyPhrase[2] == menuItemStr[i + 1]) &&
  1178.                     (gKeyPhrase[3] == menuItemStr[i + 2]) &&
  1179.                     (gKeyPhrase[4] == menuItemStr[i + 3]) &&
  1180.                     (gKeyPhrase[5] == menuItemStr[i + 4]))
  1181.                 {
  1182.                     // Found the key phrase
  1183.                     foundKey = true;
  1184.                     break;
  1185.                 }
  1186.             }
  1187.             
  1188.             // Did we find the key phrase?
  1189.             if (foundKey)
  1190.             {
  1191.                 // Copy the instance string
  1192.                 BlockMove ((Ptr)&menuItemStr[i + 5], (Ptr)&instanceStr[1], 
  1193.                     menuItemStr[0] - (i + 4));
  1194.                 instanceStr[0] = menuItemStr[0] - (i + 4);
  1195.                     
  1196.                 // Get the instance number from the string
  1197.                 HexStrToDecimalNumber ((StringPtr)&instanceStr, (long *)&gCurrentInstance);
  1198.                 
  1199.                 // Update the menus
  1200.                 AdjustMenus();
  1201.                 
  1202.                 // Get the description for this instance
  1203.                 result = GetComponentInfo ((Component) gCurrentInstance, 
  1204.                     &mathDesc, nil, nil, nil);
  1205.                 GetIndString (gStatusStr, kStatusStrsID, kCompDescStr);
  1206.                 BlockMove ((Ptr)&(mathDesc.componentType), 
  1207.                     (Ptr)&(gStatusStr[gStatusStr[0] + 1]), 4);
  1208.                 gStatusStr[0] += 4;
  1209.                 gStatusStr[gStatusStr[0] + 1] = ',';
  1210.                 gStatusStr[gStatusStr[0] + 2] = ' ';
  1211.                 gStatusStr[0] += 2;
  1212.                 BlockMove ((Ptr)&(mathDesc.componentSubType), 
  1213.                     (Ptr)&(gStatusStr[gStatusStr[0] + 1]), 4);
  1214.                 gStatusStr[0] += 4;
  1215.                 gStatusStr[gStatusStr[0] + 1] = ',';
  1216.                 gStatusStr[gStatusStr[0] + 2] = ' ';
  1217.                 gStatusStr[0] += 2;
  1218.                 BlockMove ((Ptr)&(mathDesc.componentManufacturer), 
  1219.                     (Ptr)&(gStatusStr[gStatusStr[0] + 1]), 4);
  1220.                 gStatusStr[0] += 4;
  1221.                 gStatusStr[gStatusStr[0] + 1] = ']';
  1222.                 gStatusStr[gStatusStr[0] + 2] = '.';
  1223.                 gStatusStr[0] += 2;
  1224.                 
  1225.                 // Update the status dialog
  1226.                 UpdateStatus();
  1227.             }            
  1228.             break;
  1229.         }
  1230.         case kCanDoID:
  1231.         {
  1232.             switch (menuItem)
  1233.             {
  1234.                 case kCanDoOpenItem:
  1235.                 {
  1236.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1237.                         kComponentOpenSelect))
  1238.                     {
  1239.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoOpenStr);
  1240.                     }
  1241.                     else
  1242.                     {
  1243.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoOpenStr);
  1244.                     }
  1245.                     UpdateStatus();
  1246.                     break;
  1247.                 }
  1248.                 case kCanDoCloseItem:
  1249.                 {
  1250.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1251.                         kComponentCloseSelect))
  1252.                     {
  1253.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoCloseStr);
  1254.                     }
  1255.                     else
  1256.                     {
  1257.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoCloseStr);
  1258.                     }
  1259.                     UpdateStatus();
  1260.                     break;
  1261.                 }
  1262.                 case kCanDoCanDoItem:
  1263.                 {
  1264.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1265.                         kComponentCanDoSelect))
  1266.                     {
  1267.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoCanDoStr);
  1268.                     }
  1269.                     else
  1270.                     {
  1271.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoCanDoStr);
  1272.                     }
  1273.                     UpdateStatus();
  1274.                     break;
  1275.                 }
  1276.                 case kCanDoVersionItem:
  1277.                 {
  1278.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1279.                         kComponentVersionSelect))
  1280.                     {
  1281.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoVersionStr);
  1282.                     }
  1283.                     else
  1284.                     {
  1285.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoVersionStr);
  1286.                     }
  1287.                     UpdateStatus();
  1288.                     break;
  1289.                 }
  1290.                 case kCanDoRegisterItem:
  1291.                 {
  1292.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1293.                         kComponentRegisterSelect))
  1294.                     {
  1295.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoRegisterStr);
  1296.                     }
  1297.                     else
  1298.                     {
  1299.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoRegisterStr);
  1300.                     }
  1301.                     UpdateStatus();
  1302.                     break;
  1303.                 }
  1304.                 case kCanDoTargetItem:
  1305.                 {
  1306.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1307.                         kComponentTargetSelect))
  1308.                     {
  1309.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoTargetStr);
  1310.                     }
  1311.                     else
  1312.                     {
  1313.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoTargetStr);
  1314.                     }
  1315.                     UpdateStatus();
  1316.                     break;
  1317.                 }
  1318.                 case kCanDoDoDivideItem:
  1319.                 {
  1320.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1321.                         kDoDivideSelect))
  1322.                     {
  1323.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoDoDivideStr);
  1324.                     }
  1325.                     else
  1326.                     {
  1327.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoDoDivideStr);
  1328.                     }
  1329.                     UpdateStatus();
  1330.                     break;
  1331.                 }
  1332.                 case kCanDoDoMultiplyItem:
  1333.                 {
  1334.                     if (ComponentFunctionImplemented (gCurrentInstance,
  1335.                         kDoMultiplySelect))
  1336.                     {
  1337.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoDoMultiplyStr);
  1338.                     }
  1339.                     else
  1340.                     {
  1341.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoDoMultiplyStr);
  1342.                     }
  1343.                     UpdateStatus();
  1344.                     break;
  1345.                 }
  1346.                 case kCanDoDoAddItem:
  1347.                 {
  1348.                     if (ComponentFunctionImplemented (gCurrentInstance, kDoAddSelect))
  1349.                     {
  1350.                         GetIndString (gStatusStr, kStatusStrsID, kCanDoDoAddStr);
  1351.                     }
  1352.                     else
  1353.                     {
  1354.                         GetIndString (gStatusStr, kStatusStrsID, kCantDoDoAddStr);
  1355.                     }
  1356.                     UpdateStatus();
  1357.                     break;
  1358.                 }
  1359.                 default:
  1360.                 {
  1361.                     break;
  1362.                 }
  1363.             }
  1364.             break;
  1365.         }
  1366.         default:
  1367.         {
  1368.             break;
  1369.         }
  1370.     }
  1371. }
  1372.  
  1373. //-----------------------------------------------------------------------
  1374.  
  1375. void    OpenStatus    (void)
  1376. {
  1377.     // Get the dialog
  1378.     gStatusDialog = GetNewDialog (kStatusDialogID, nil, (WindowPtr)-1L);
  1379.     
  1380.     // Did we get it?
  1381.     if (gStatusDialog != nil)
  1382.     {
  1383.         short    itemType;
  1384.         
  1385.         GetPort (&gSavedPort);
  1386.         SetPort (gStatusDialog);
  1387.         TextFont (geneva);
  1388.         TextFace (0);
  1389.         TextSize (10);
  1390.         GetDItem (gStatusDialog, kStatusBox, &itemType, &gStatusText, &gStatusBox);
  1391.         InsetRect (&gStatusBox, -2, -2);
  1392.         FrameRect (&gStatusBox);
  1393.         InsetRect (&gStatusBox, 2, 2);
  1394.         EraseRect (&gStatusBox);
  1395.         SetIText (gStatusText, gStatusStr);
  1396.     }
  1397.     
  1398.     // Update the menus
  1399.     AdjustMenus();
  1400. }
  1401.  
  1402. //-----------------------------------------------------------------------
  1403.  
  1404. void    UpdateStatus    (void)
  1405. {
  1406.     // If we've got a status dialog, update it
  1407.     if (gStatusDialog != nil)
  1408.     {
  1409.         GetPort (&gSavedPort);
  1410.         SetPort (gStatusDialog);
  1411.         InvalRect (&gStatusBox);
  1412.         SetPort (gSavedPort);
  1413.     }
  1414. }
  1415.  
  1416. //-----------------------------------------------------------------------
  1417.  
  1418. void    OpenMathComponent    (MathType    whichOne)
  1419. {
  1420.     short        i;
  1421.     Str255        tempStr;
  1422.     Component    mathComponentID;
  1423.     short        mathTypeStrID;
  1424.     Boolean        foundSlot = false;
  1425.     
  1426.     // Which type of component do we want to open?
  1427.     switch (whichOne)
  1428.     {
  1429.         case kMathComponent:
  1430.             mathComponentID = gMathComponentID;
  1431.             mathTypeStrID = kMathStr;
  1432.             break;
  1433.         case kMoMathComponent:
  1434.             mathComponentID = gMoMathComponentID;
  1435.             mathTypeStrID = kMoMathStr;
  1436.             break;
  1437.         case kNuMathComponent:
  1438.             mathComponentID = gNuMathComponentID;
  1439.             mathTypeStrID = kNuMathStr;
  1440.             break;
  1441.         default:
  1442.             break;
  1443.     }
  1444.     
  1445.     // Were we asked to open some type of Math component?
  1446.     if (mathComponentID != 0L)
  1447.     {
  1448.         // Find an open slot
  1449.         for (i = 0; i < kMaxInstances; i++)
  1450.         {
  1451.             // Is this slot open?
  1452.             if (gComponentInstance[i] == 0L)
  1453.             {
  1454.                 // Open the component
  1455.                 gComponentInstance[i] = 
  1456.                     (MathComponent) OpenComponent (mathComponentID);
  1457.                 gCurrentInstance = gComponentInstance[i];
  1458.                 foundSlot = true;
  1459.                 break;
  1460.             }
  1461.         }
  1462.     }
  1463.     else    // We were not asked to find some kind of Math component
  1464.     {
  1465.         GetIndString (gStatusStr, kStatusStrsID, kDidNotFindCompIDStr);
  1466.     }
  1467.     
  1468.     // There were no open slots (we've opened as many instances as our test
  1469.     // program will allow)
  1470.     if (!foundSlot)
  1471.     {
  1472.         GetIndString (gStatusStr, kStatusStrsID, kCantOpenAnyMoreInstStr);
  1473.     }
  1474.     else if (gCurrentInstance != 0L)    // We successfully opened the component
  1475.     {
  1476.         Str255    mathTypeStr;
  1477.         
  1478.         GetIndString (mathTypeStr, kStatusStrsID, mathTypeStrID);
  1479.         GetIndString (gStatusStr, kStatusStrsID, kFoundCompIDAndInstStr);
  1480.         DecimalNumberToHexStr ((long) gCurrentInstance, (StringPtr)&tempStr);
  1481.         BlockMove ((Ptr)&tempStr[1], (Ptr)&mathTypeStr[mathTypeStr[0] + 1],
  1482.             tempStr[0]);
  1483.         mathTypeStr[0] += tempStr[0];
  1484.         InsMenuItem (gInstanceMenu, mathTypeStr, 255);
  1485.     }
  1486.     else    // We couldn't open an instance of the component
  1487.     {
  1488.         GetIndString (gStatusStr, kStatusStrsID, kDidNotGetInstStr);
  1489.     }
  1490.     
  1491.     // Update everything
  1492.     UpdateStatus();
  1493.     AdjustMenus();
  1494. }
  1495.  
  1496. //-----------------------------------------------------------------------
  1497.  
  1498. void    DoAboutDialog    (void)
  1499. {
  1500.     short        itemHit;
  1501.     short        itemType;
  1502.     Handle        itemHandle;
  1503.     Rect        itemRect;
  1504.     DialogPtr    aboutDialog = GetNewDialog (kAboutDialogID, nil, (WindowPtr)-1L);
  1505.     UserItemUPP DrawOKOutlineUPP = NewUserItemProc(DrawOKOutline);    
  1506.  
  1507.     // Do the boring about dialog
  1508.     GetDItem (aboutDialog, kOKButtonOutline, &itemType, &itemHandle, &itemRect);
  1509.     SetDItem (aboutDialog, kOKButtonOutline, itemType, 
  1510.         (Handle) DrawOKOutlineUPP, &itemRect);
  1511.     do
  1512.     {
  1513.         ModalDialog (nil, &itemHit);
  1514.     }
  1515.     while (itemHit != kOKButton);
  1516.     DisposDialog (aboutDialog);
  1517. }
  1518.  
  1519. //-----------------------------------------------------------------------
  1520.  
  1521. void    DoOperationDialog    (short    *firstNum,
  1522.                              short    *secondNum)
  1523. {
  1524.     DialogPtr    opDialog = GetNewDialog (kOpDialogID, nil, (WindowPtr)-1L);
  1525.     
  1526.     // Did we get a dialog?
  1527.     if (opDialog != nil)
  1528.     {
  1529.         short    itemHit;
  1530.         short    itemType;
  1531.         Handle    itemHandle;
  1532.         Rect    itemRect;
  1533.         Str255    tempStr;
  1534.         long    tempNum;
  1535.         
  1536.         GetDItem (opDialog, kFirstNumBox, &itemType, &itemHandle, &itemRect);
  1537.         NumToString (23L, tempStr);
  1538.         SetIText (itemHandle, tempStr);
  1539.         
  1540.         GetDItem (opDialog, kSecondNumBox, &itemType, &itemHandle, &itemRect);
  1541.         NumToString (4L, tempStr);
  1542.         SetIText (itemHandle, tempStr);
  1543.         
  1544.         // Go get two numbers from the user
  1545.         do
  1546.         {
  1547.             ModalDialog (nil, &itemHit);
  1548.         }
  1549.         while (itemHit != kOKButton);
  1550.         
  1551.         // Give the two numbers back to the caller
  1552.         GetDItem (opDialog, kFirstNumBox, &itemType, &itemHandle, &itemRect);
  1553.         GetIText (itemHandle, tempStr);
  1554.         StringToNum (tempStr, &tempNum);
  1555.         *firstNum = (short) tempNum;
  1556.         
  1557.         GetDItem (opDialog, kSecondNumBox, &itemType, &itemHandle, &itemRect);
  1558.         GetIText (itemHandle, tempStr);
  1559.         StringToNum (tempStr, &tempNum);
  1560.         *secondNum = (short) tempNum;
  1561.         
  1562.         // Clean up
  1563.         DisposDialog (opDialog);
  1564.     }
  1565. }
  1566.  
  1567. //-----------------------------------------------------------------------
  1568.  
  1569. static    pascal    void    DrawOKOutline    (DialogPtr    theDialog,
  1570.                                          short        theItem)
  1571. {
  1572.     short    itemType;
  1573.     Handle    itemHandle;
  1574.     Rect    itemRect;
  1575.     
  1576.     // Draws the OK button outline
  1577.     SetPort (theDialog);
  1578.     GetDItem (theDialog, kOKButtonOutline, &itemType, &itemHandle, &itemRect);
  1579.     PenSize (3, 3); 
  1580.     InsetRect (&itemRect, -4, -4);
  1581.     FrameRoundRect (&itemRect, 16, 16);
  1582.     PenSize (1, 1);
  1583. }
  1584.  
  1585. //-----------------------------------------------------------------------
  1586.  
  1587. void    DoQuit    (void)
  1588. {
  1589.     ComponentResult    result = noErr;
  1590.     short            i;
  1591.     
  1592.     // Walk our instance array and close all instances
  1593.     for (i = 0; i < kMaxInstances; i++)
  1594.     {
  1595.         if (gComponentInstance[i] != 0L)
  1596.         {
  1597.             result = CloseComponent (gComponentInstance[i]);
  1598.             gComponentInstance[i] = 0L;
  1599.         }
  1600.     }
  1601.     // Note that it's not necessary to unregister the components
  1602.     // or dispose of the string handles for the name and info
  1603.     // strings when we're in debug mode - this is because we registered 
  1604.     // the components locally, and as soon as the application heap 
  1605.     // shuts down (that is, the app quits), the Component Manager 
  1606.     // automatically unregisters any components local to that app heap and 
  1607.     // disposes of the component handles properly.
  1608.     
  1609.     // Set quit flag
  1610.     gQuitFlag = true;
  1611. }
  1612.  
  1613. //-----------------------------------------------------------------------
  1614.  
  1615. void    DecimalNumberToHexStr    (long        theDecimalNumber,
  1616.                                  StringPtr    theHexStr)
  1617. {
  1618.     // Utility routine to convert a decimal number into a
  1619.     // hex number string    
  1620.     
  1621.     long    testNybble;
  1622.     char    hexStr[8];
  1623.     Str255    tempStr;
  1624.     short    i;
  1625.     
  1626.     for (i = 7; i >= 0; i--)
  1627.     {
  1628.         testNybble = (theDecimalNumber & (0xF0000000 >> (4 * i))) >> ((7 - i) * 4);
  1629.         
  1630.         if ((testNybble == 8) || (testNybble == 9))    // is it 8 or 9?
  1631.         {
  1632.             NumToString (testNybble, tempStr);
  1633.             hexStr[i] = tempStr[1];
  1634.         }
  1635. //MA changed
  1636. //        else if ((testNybble & 0x00000008) == 1)    // is it between A and F?
  1637.         else if ((testNybble & 0x00000008))    // is it between A and F?
  1638.         {
  1639.             if (testNybble == 10)
  1640.                 hexStr[i] = 'A';
  1641.             else if (testNybble == 11)
  1642.                 hexStr[i] = 'B';
  1643.             else if (testNybble == 12)
  1644.                 hexStr[i] = 'C';
  1645.             else if (testNybble == 13)
  1646.                 hexStr[i] = 'D';
  1647.             else if (testNybble == 14)
  1648.                 hexStr[i] = 'E';
  1649.             else if (testNybble == 15)
  1650.                 hexStr[i] = 'F';
  1651.         }
  1652.         else                                        // it's between 0 and 7
  1653.         {
  1654.             NumToString (testNybble, tempStr);
  1655.             hexStr[i] = tempStr[1];
  1656.         }
  1657.     }
  1658.     BlockMove ((Ptr)&hexStr, (Ptr)&theHexStr[1], 8);
  1659.     theHexStr[0] = 8;
  1660. }
  1661.  
  1662. //-----------------------------------------------------------------------
  1663.  
  1664. OSErr    HexStrToDecimalNumber    (StringPtr    theHexStr,
  1665.                                  long        *theDecimalNumber)
  1666. {
  1667.     // Utility routine to convert a hex number string into
  1668.     // a decimal number
  1669.     
  1670.     OSErr    result = noErr;
  1671.     long    decimalNum = 0L;
  1672.     short    i;
  1673.     long    hexDigitValue;
  1674.     Str255    tempStr;
  1675.     
  1676.     tempStr[0] = 1;
  1677.     if (theHexStr[0] > 8)
  1678.     {
  1679.         result = kGenericError;
  1680.     }
  1681.     else
  1682.     {
  1683.         for (i = 1; i <= 8; i++)
  1684.         {
  1685.             if (theHexStr[i] >= 0x30 && theHexStr[i] <= 0x39)    // it's between 0 and 9
  1686.             {
  1687.                 tempStr[1] = theHexStr[i];
  1688.                 StringToNum (tempStr, &hexDigitValue);
  1689.                 decimalNum += hexDigitValue << (4 * (8 - i));
  1690.             }
  1691.             else if ((theHexStr[i] >= 0x41 && theHexStr[i] <= 0x46) ||
  1692.                 (theHexStr[i] >= 0x61 && theHexStr[i] <= 0x66))    // it's between A and F
  1693.             {
  1694.                 switch (theHexStr[i])
  1695.                 {
  1696.                     case 'A':
  1697.                     case 'a':
  1698.                         hexDigitValue = 10;
  1699.                         break;
  1700.                     case 'B':
  1701.                     case 'b':
  1702.                         hexDigitValue = 11;
  1703.                         break;
  1704.                     case 'C':
  1705.                     case 'c':
  1706.                         hexDigitValue = 12;
  1707.                         break;
  1708.                     case 'D':
  1709.                     case 'd':
  1710.                         hexDigitValue = 13;
  1711.                         break;
  1712.                     case 'E':
  1713.                     case 'e':
  1714.                         hexDigitValue = 14;
  1715.                         break;
  1716.                     case 'F':
  1717.                     case 'f':
  1718.                         hexDigitValue = 15;
  1719.                         break;
  1720.                 }
  1721.                 decimalNum += hexDigitValue << (4 * (8 - i));
  1722.             }
  1723.             else
  1724.             {
  1725.                 result = kGenericError;
  1726.             }
  1727.         }
  1728.     }
  1729.     
  1730.     *theDecimalNumber = decimalNum;    
  1731.     return (result);
  1732. }
  1733.                              
  1734. //-----------------------------------------------------------------------
  1735.  
  1736.